﻿namespace Modbus
{
    using System;
    using System.Globalization;
    using System.Runtime.Serialization;

    /// <summary>
    /// 无效的modbus请求异常类。
    /// </summary>
    [Serializable]
    public class InvalidModbusRequestException : Exception
    {
        /// <summary>
        /// 只读异常代码
        /// </summary>
        private readonly byte _exceptionCode;

        /// <summary>
        /// 使用指定的Modbus异常代码初始化一个实例。
        /// </summary>
        /// <param name="exceptionCode">提供给slave的Modbus异常代码。</param>
        public InvalidModbusRequestException(byte exceptionCode)
            : this(GetMessage(exceptionCode), exceptionCode) { }

        /// <summary>
        /// 使用指定的错误消息和Modbus异常代码初始化实例。
        /// </summary>
        /// <param name="message">解释异常原因的错误消息。</param>
        /// <param name="exceptionCode">提供给slave的Modbus异常代码。</param>
        public InvalidModbusRequestException(string message, byte exceptionCode)
            : this(message, exceptionCode, null) { }

        /// <summary>
        /// 使用指定的Modbus异常代码和引起该异常的内部异常的初始化实例。
        /// </summary>
        /// <param name="exceptionCode">提供给slave的Modbus异常代码。</param>
        /// <param name="innerException">导致当前异常的颞部异常。如果<paramref name="innerException" /> 不是空引用, 当前异常将在处理内部异常的catch块中引发。</param>
        public InvalidModbusRequestException(byte exceptionCode, Exception innerException)
            : this(GetMessage(exceptionCode), exceptionCode, innerException) { }

        /// <summary>
        /// 使用指定的错误消息、Modbus异常代码和引起该异常的内部异常初始化实例。
        /// </summary>
        /// <param name="message">解释异常原因的错误消息。</param>
        /// <param name="exceptionCode">提供给slave的Modbus异常代码。</param>
        /// <param name="innerException">导致当前异常的异常。如果形参<paramref name="innerException" />不是空引用，当前异常将在处理内部异常的catch块中引发。</param>
        public InvalidModbusRequestException(string message, byte exceptionCode, Exception innerException)
            : base(message, innerException)
        {
            _exceptionCode = exceptionCode;
        }

        /// <summary>
        /// 使用序列化的数据和上下文信息初始化实例。    
        /// </summary>
        /// <param name="info">异常的序列化对象数据。</param>
        /// <param name="context">关于源或目标的上下文信息。</param>
        protected InvalidModbusRequestException(SerializationInfo info, StreamingContext context)
            : base(info, context) { }

        /// <summary>
        /// 使用Modbus异常代码和其他异常信息设置对象。
        /// </summary>
        /// <param name="info">异常的序列化对象数据。</param>
        /// <param name="context">关于源或目标的上下文信息。</param>
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("ExceptionCode", this._exceptionCode, typeof(byte));
        }

        /// <summary>
        /// 获取要提供给从设备的Modbus异常代码。
        /// </summary>
        public byte ExceptionCode
        {
            get { return _exceptionCode; }
        }

        /// <summary>
        /// 获取异常消息内容
        /// </summary>
        /// <param name="exceptionCode">异常标识</param>
        /// <returns>返回错误消息</returns>
        private static string GetMessage(byte exceptionCode)
        {
            return string.Format(CultureInfo.InvariantCulture, "Modbus exception code {0}.", (int)exceptionCode);
        }
    }
}
